﻿using System;
using System.Collections.Generic;
using System.Drawing;

namespace CC.Utilities.Drawing
{
    /// <summary>
    /// Static "extension" methods used to build <see cref="Font"/>
    /// </summary>
    public static class FontBuilder
    {
        #region Private Constants
        // ReSharper disable InconsistentNaming
        private const string ARGUMENT_EXCEPTION_TEXT = "Invalid string supplied. Input string must come from Font.ToString() or Font.ToStringEx()\r\n\r\n{0}";
        // ReSharper restore InconsistentNaming
        #endregion

        #region Public Methods
        /// <summary>
        /// Creates a new <see cref="Font"/> based on a list of <see cref="Font"/> names used for fallback.
        /// </summary>
        /// <param name="fontNames">The comma seperated list of <see cref="Font"/> names</param>
        /// <param name="emSize">The size of the new <see cref="Font"/></param>
        /// <param name="style">The <see cref="FontStyle"/> of the new <see cref="Font"/></param>
        /// <param name="unit">The <see cref="GraphicsUnit"/> of the new <see cref="Font"/></param>
        /// <returns></returns>
        public static Font FromFontNames(string fontNames, float emSize, FontStyle style, GraphicsUnit unit)
        {
            Font returnValue = null;

            if (!string.IsNullOrEmpty(fontNames))
            {
                foreach (string fontName in fontNames.Split(','))
                {
                    string tempFontName = fontName.Trim();

                    returnValue = new Font(tempFontName, emSize, style, unit);

                    if (returnValue.Name.Equals(tempFontName, StringComparison.InvariantCultureIgnoreCase))
                    {
                        break; // Font name matched
                    }

                    returnValue.Dispose();
                    returnValue = null;
                }
            }

            if (returnValue == null)
            {
                returnValue = new Font("Microsoft Sans Serif", emSize, style, unit);
            }

            return returnValue;
        }

        /// <summary>
        /// Creates a <see cref="Font"/> from a string generated by either <see cref="Font"/>.ToString() or <see cref="Font"/>.ToStringEx()
        /// </summary>
        /// <param name="fontString">The string to build the <see cref="Font"/> from</param>
        /// <returns>A <see cref="Font"/> from the supplied string</returns>
        public static Font FromString(string fontString)
        {
            Font returnValue;

            if (fontString.StartsWith("[Font: ") && fontString.EndsWith("]"))
            {
                fontString = fontString.Remove(0, 7);
                fontString = fontString.Remove(fontString.Length - 1, 1);

                string[] parameters = fontString.Split(new [] {','});
                Dictionary<string, string> fontParameters = new Dictionary<string, string>();

                foreach (string parameter in parameters)
                {
                    string[] keyValue = parameter.Trim().Split(new [] {'='});
                    if (keyValue.Length == 2)
                    {
                        fontParameters.Add(keyValue[0], keyValue[1]);
                    }
                }

                switch (fontParameters.Count)
                {
                    case 5: // This is the only one I need for ToString() I believe ...
                        {
                            if (fontParameters.ContainsKey("Name") && fontParameters.ContainsKey("Size") && fontParameters.ContainsKey("Units") && fontParameters.ContainsKey("GdiCharSet") && fontParameters.ContainsKey("GdiVerticalFont"))
                            {
                                returnValue = new Font(fontParameters["Name"], float.Parse(fontParameters["Size"]), FontStyle.Regular, (GraphicsUnit)int.Parse(fontParameters["Units"]), byte.Parse(fontParameters["GdiCharSet"]), bool.Parse(fontParameters["GdiVerticalFont"]));
                            }
                            else
                            {
                                throw new ArgumentException(string.Format(ARGUMENT_EXCEPTION_TEXT, fontString), "fontString");
                            }
                            break;
                        }
                    case 6: // This is the only one I need for ToStringEx() (for now...)
                        {
                            if (fontParameters.ContainsKey("Name") && fontParameters.ContainsKey("Size") && fontParameters.ContainsKey("Units") && fontParameters.ContainsKey("GdiCharSet") && fontParameters.ContainsKey("GdiVerticalFont") && fontParameters.ContainsKey("Style"))
                            {
                                returnValue = new Font(fontParameters["Name"], float.Parse(fontParameters["Size"]), (FontStyle) int.Parse(fontParameters["Style"]), (GraphicsUnit) int.Parse(fontParameters["Units"]), byte.Parse(fontParameters["GdiCharSet"]), bool.Parse(fontParameters["GdiVerticalFont"]));
                            }
                            else
                            {
                                throw new ArgumentException(string.Format(ARGUMENT_EXCEPTION_TEXT, fontString), "fontString");                                
                            }
                            break;
                        }
                    default:
                        {
                            throw new ArgumentException(string.Format(ARGUMENT_EXCEPTION_TEXT, fontString), "fontString");
                        }
                }
            }
            else
            {
                throw new ArgumentException(string.Format(ARGUMENT_EXCEPTION_TEXT, fontString), "fontString");
            }

            return returnValue;
        }
        #endregion
    }
}
